/**
 * Created by mapbar_front on 2019/5/12.
 */
import React, {Component} from 'react';

/*
//工厂模式
function createPerson(name, age) {
    var person = new Object();
    person.name = name;
    person.age = age;
    person.sayName = function () {
        return this;
    }
    return person;
}
var person1 = createPerson('tianxia', 18);
var person2 = createPerson('xiaoxiao', 22);

console.log(person1);
console.log(person2);

//构造函数模式
function Person(name, age) {
    console.log('this是', this);
    this.name = name;
    this.age = age;
    this.sayName = function () {
        return this.name;
    }
}

var person1 = new Person('tianxia', 18);
var person2 = new Person('xiaoxiao', 22);
//new Person() 发生了什么？
// 1.创建一个新的对象（var obj = new Object() ）
// 2.将this指向新对象，原本this指向window
// 3.执行构造函数中内容，给新的对象添加属性和方法。
// 4.返回新的对象。

var obj = new Object();
//new Object() 又发生了什么？
//使用构造函数Object，为新的对象定义了默认的属性和方法。
//为何new Object() 不会执行上面的四步骤。
console.log(person1);
console.log('person1', person1.constructor == Person);
console.log('person2', person2.constructor == Person);

//检测是不是Object和Person的实例,所有的对象都是构造函数Object的实例。
console.log(person1 instanceof Person);
console.log(person1 instanceof Object);

console.log(person2 instanceof Person);
console.log(person2 instanceof Object);

function Personaa(name, age) {
    console.log('Person1', this);

}
//console.log('最外层的this是',this);
//作为普通函数调用
Personaa('woa', 11);
//window.sayName();

//在另一个对象中的作用域中调用
var o = new Object();
Person.call(o, 'woaini', 18);
console.log('o', o);

console.log(person1.sayName == person2.sayName); //false


function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = sayName;
}
function sayName() {
    console.log('this.name++', this.name);
}

var person1 = new Person('xiaoxiao1', 1);
//person1.sayName();
var person2 = new Person('tianxia1', 2);

// function Person(name,age) {
//     this.name = name;
//     this.age = age;
//     this.sayName = new Function( console.log(this.name) )
// }

// if(!("a" in window)) {
//     var a = 1;
// }
// console.log(a);
//
// var a = 1,b = function a(x) {
//     x&&a(--x);
// }
// console.log(a)
//
// function b(x,y,a) {
//  a = 8;
//  arguments[2] = 10;
//  console.log(a);
// }
// b(1,2,3);
//
// (function f(f){
//     console.log(typeof f());
// })(function(){ return 1;})

// var car = {
//     price: 15,
//     run: function() {
//         return this.price
//     }
// }
// console.log(typeof(f = car.run)());

// var a = 1;
// if(function(){}){
//     a+=typeof f;
// }
// console.log(a);
//
// var obj = {
//     value: 3,
//     fun: function() {
//         return this.value;
//     }
// }
// var fun = function() {
//     this.value =  this.fun.apply(window) + "1";
// }
// fun.prototype = obj;
// console.log(new fun().value);

// class A{
//     constructor() {
//         this.a = 1;
//     }
//     aFun() {
//
//     }
// }
// class B extends A {
//     constructor() {
//         super();
//         this.b = 2;
//     }
//     bFun(){}
// }
// let obj = new B();
// console.log(window.B);


// let arr = [];
// setTimeout(function() {
//     arr.push(1);
// })
// Promise.resolve().then(()=>{
//     arr.push(2);
// })
// new Promise(()=>{
//     arr.push(7);
// })
// async function a() {
//     arr.push(3);
//     await  b()
//     arr.push(4);
// }
// async function b() {
//     arr.push(5)
// }
// a()
// arr.push(6);
//
// setTimeout(()=>{
//     console.log(arr.join(''));
// })


//普通函数也有prototype属性
function fn1() {

}
console.log('fn1', fn1.prototype);

//原型模式
function Person() {

}
Person.prototype.name = '天下';
Person.prototype.age = 18;
Person.prototype.sayName = function () {
    console.log(this.name);
}
var person1 = new Person();
person1.sayName();
var person2 = new Person();

console.log(person1);
console.log(person2);

//原型上的方法分配的是同一块地址
console.log(person1.sayName === person1.sayName); //true
//虽然在所有实现中都无法访问到[[prototype]],但可以通过isPrototypeOf()方法来确定对象之间是否存在这种
//对应的关系
//从本质上讲，如果[[Prototype]]指向调用isPrototypeOf()方法的对象（Person.prototype）
console.log(Person.prototype.isPrototypeOf(person1));
console.log(Person.prototype);
console.log(person1);

//ECMAScript5 增加了一个新的方法，叫Object.getPrototypeOf(),在所有支持的实现中，这个方法返回
//[[Prototype]]的值。
console.log(Object.getPrototypeOf(person1) == Person.prototype);
console.log(Object.getPrototypeOf(person2) == Person.prototype);

//虽然我们可以通过实例访问原型中的值，但不能通过对象实例重写原型的值。
person1.name = '丽江';
person1.sayName();  //丽江——来自实例
person2.sayName();  //天下——来自原型

//当为对象实例添加一个属性时，这个属性就会屏蔽原型对象中保存的同名属性。
delete person1.name;
person1.sayName(); //天下——来自原型
//使用hasOwnProperty()方法可以检测一个属性是存在实例中，还是原型中。
// 这个方法（不要忘了它是从Object中继承来的）只在给定属性存在对象实例中，才会返回true。
//hasOwnProperty() 如何用？
//person1.hasOwnProperty('age');
console.log(person1.hasOwnProperty('age')); //false
person1.job = 'web前端工程师';
console.log(person1.hasOwnProperty('job')); //true

//getOwnPropertyDescriptor()
var descriptor = Object.getOwnPropertyDescriptor(person1, 'job');
console.log(descriptor);
var descriptor = Object.getOwnPropertyDescriptor(Person.prototype, 'age');
console.log(descriptor);
console.log(Object.getPrototypeOf(person1));

//原型与in操作符
//有两种方式使用in操作符，一种是单独使用，一种是for-in。
//在单独使用时，in操作符会在通过对象能够访问给定属性时返回true，无论存在对象中还是原型中。

console.log('job' in person1); //true
//判断一个属性是不是实例属性 hasOwnProperty();
console.log(person1.hasOwnProperty('job')); //true ——来自实例

console.log(person1.hasOwnProperty('name')); //false ——来自原型
console.log('name' in person1); //true

//确定一个属性是存在实例中还是原型对象中，用in操作符和hasOwnProperty()
if (person1.hasOwnProperty('job') && ('job' in person1)) {
    console.log('该属性存在实例中');
}
if (!person1.hasOwnProperty('name') && 'name' in person1) {
    console.log('该属性存在于原型对象中');
}
//函数需要封装

function hasPrototypeProperty(name, obj) {
    return !obj.hasOwnProperty(name) && (name in obj);
}
//原型对象中的name
console.log(hasPrototypeProperty('name', person1)); //true
console.log(hasPrototypeProperty('job', person1)); //false

//for-in 实例，看能否遍历出所有的属性 原型对象中的属性和方法也遍历出来了。
for (var prop in person1) {
    console.log(person1[prop]);
}
Object.defineProperty(person1, 'name', {
    //如果设置为false，下面就不会遍历到
    enumerable: false,
    value: 123,
});
//
var descriptor = Object.getOwnPropertyDescriptor(person1, 'age');
//什么都得不到，不明确此方法如何用的缘故？ 在原型上的属性居然用此方法得不到为何？
//原因是 Object.getOwnPropertyDescriptor() 方法的用法
//Object.getOwnPropertyDescriptor()可以取得给定属性的描述符，这个方法接受两个参数：
// 1.属性所在的对象 在这里，如果是person1，只能读取实例中的属性，原型对象中的属性无法读取。
// 2.要读取其描述符的属性名称。如果是原型方法，只能读取原型中的属性。


var descriptor = Object.getOwnPropertyDescriptor(Person.prototype, 'age');
console.log(descriptor);
var descriptor = Object.getOwnPropertyDescriptor(person1, 'name');
console.log(descriptor);


// for(var prop in person1) {
//     console.log(person1[prop]);
// }
// person1.toString = function() {
//     return 'My Object';
// }
for (var prop in person1) {
    if (prop == 'toString') {
        console.log('person1[prop]', person1[prop]);
    }
}
//Object.keys() 取对象上所有可枚举的实例属性
console.log(Object.keys(person1));

//Object.getOwnProtyNames() 得到所有实例属性，无论它是否可枚举。 包含不可枚举类型的constructor
console.log(Object.getOwnPropertyNames(person1));
console.log(Object.getOwnPropertyNames(Person.prototype));


function hasPrototypeProperty(name, object) {
    return object.hasOwnProperty(name) && ( name in object);
}
console.log(hasPrototypeProperty('job', person1));

//3.更简单的原型方法
//之前，我们每添加一次属性和方法都要敲一次Person.prototype,为了减少不必要的输入，
// 也为了视觉上的更好的封装原型的功能，更常见的做法是用字面量对象重写原型。
function Person1() {

}
//Person1.prototype.name = 'xiaoxiao';

//下面这句话放在Person1.prototype前和放在后有什么区别呢？
//var friend = new Person1();
Person1.prototype = {
    constructor: Person1,
    name: 'tianxia1',
    age: 1,
    job: 'web前端工程师1',
    sayName: function () {
        console.log(this.name);
    }
}
//放在这里和前面有什么区别呢？
var friend = new Person1();

console.log(friend);
//这里的constructor不再指向构造函数Person1，而是指向构造函数Object
console.log(Person1.prototype.constructor == Person1); //false
console.log(Person1.prototype.constructor == Object); //true

//instanceof 检测对象类型 用来检测Person1.prototype 是否存在于参数friend的原型
console.log('instanceof1', friend instanceof Person1); //true
console.log('instanceof2', friend instanceof Object);  //true

//Object.getOwnPropertyof(); 这个方法返回原型对象的值
console.log(Object.getPrototypeOf(person1));
//构造函数Object的原型是什么？
console.log(Person1.prototype == Object.getPrototypeOf(person1)); //true


for (var prop in Person1.prototype) {
    console.log(prop);
}

Object.defineProperty(Person1.prototype, "constructor", {
    enumerable: false,
    value: Person1,
});
for (var prop in Person1.prototype) {
    console.log(prop);
}

//构造函数Person2
function Person2() {

}

Person2.prototype.name = 'tianxia';
//Person2.prototype.constructor 指向 Person2
console.log('Person2.prototype', Person2.prototype);

//这样定义的话，Person2.prototype 就没有constructor属性，为何？
Person2.prototype = {
    name: 'tianxia2',
    age: 2,
    sayName: function () {
        //console.log(this.name);
    }
}
//Person2.prototype.constructor 指向 Object
//Person2.prototype 经过重新它自己没有了constructor属性，因此沿着原型链向上找。
console.log('指向Object', Person2.prototype.constructor);

var friend = new Person2();
//instanceof 确定实例和构造函数的关系
console.log(friend instanceof Person2); //true
console.log(friend instanceof Object);  //true

console.log(Person2.prototype.constructor == Person2); //false
console.log(Person2.prototype.constructor == Object);  //true

Person2.prototype = {
    constructor: Person2,
    name: 'xiaoxiao',
    age: 2,
    sayName: function () {
        console.log(this.name);
    }
}
console.log(Person2.prototype);
//如果检测enumerable的属性是false还是true。
var des = Object.getOwnPropertyDescriptor(Person2.prototype, 'constructor');
console.log('des', des);
//遍历出了constructor属性
for (var prop in Person2.prototype) {
    console.log(prop);
}
Object.defineProperty(Person2.prototype, 'constructor', {
    enumerable: false,
    value: Person2,
});
//再次遍历
for (var prop in Person2.prototype) {
    console.log(prop); //发现没有constructor属性
}
console.log('测试', Person2.prototype);

function Person3() {
}

Person3.prototype = {
    name: 'xiao0411',
    age: 22,
    sayName: function () {
        console.log(this.name);
    }
}
var friend = new Person3();
console.log(friend.__proto__);
friend.sayName(); //TypeError: friend.sayName is not a function

var string = new String();
console.log(string);
console.log(String.prototype);
String.prototype.startWith = function (text) {
    return this.indexOf(text) == 0;
}
var str = 'Hello,World';
var res = str.startWith('Hello');
console.log('res', res);

function Person4() {
}
Person4.prototype = {
    name: '天下',
    age: 18,
    colors: ['yellow', 'blue', 'green'],
    sayName: function () {
        console.log(this.name);
    }
}
var person41 = new Person4();
var person42 = new Person4();
person41.name = '改变之后的天下';
person41.colors.push('purple');
console.log(person41);
console.log(person42);
//共用同一块内存，因为在原型方法上，因此是同一块内存
console.log(person41.colors == person42.colors);

function Person5(name, age) {
    this.name = name;
    this.age = age;
    this.colors = ['yellow', 'blue', 'green']
}
Person5.prototype.sayName = function () {
    console.log(this.name);
}

var person51 = new Person5('tianxia', 22);
var person52 = new Person5('xiaoxiao', 18);

person51.colors.push('purple');
console.log(person51);
console.log(person52);
//不是同一块内存，因为在各自的实例上，相当于私有属性，因此分配的不是同一块内存地址。
console.log(person51.colors == person52.colors); //false

//6.2.5 动态原型模式
function Person6(name, age) {
    this.name = name;
    this.age = age;
    if (typeof this.sayName != 'function') {
        Person6.prototype.sayName = function () {
            console.log(this.name);
        }
    }
}
var person61 = new Person6('tianxia666', 666);
person61.sayName();

console.log(person61 instanceof Person6); //true

//6.2.6 寄生构造函数模型
function Person7(name, age) {
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.sayName = function () {
        console.log(this.name);
    }
    return obj;
}
var person71 = new Person7('xiao', 18);
person71.sayName();

function Person8() {
    return {name: 123};
}
var person81 = new Person8();
console.log(person81);

function Person9(name, age) {
    this.name = name;
    this.age = age;
}
var person91 = new Person9('tianxia', 1);
console.log(person91);


function Person10(name, age) {
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.sayName = function () {
        console.log(this.name);
    }
    return obj;
}
var person101 = new Person10('xiao', 666);
person101.sayName();

function SpecialArray() {
    //创建数组
    var values = new Array();
    //添加数组
    //console.log('arguments',arguments);
    values.push.apply(values, arguments);
    //添加方法
    values.toPipedString = function () {
        return this.join('|');
    }
    //返回数组
    return values;
}
var colors = new SpecialArray('yellow', 'blue', 'green');
console.log(colors.toPipedString());
console.log(colors instanceof SpecialArray); //false


// function arrFn(arr) {
//     console.log(arguments);
// }
// var arr = ['yellow','blue','purple'];
// var arr1 = ['aa'];
// arrFn(arr,arr1);

//6.2.7 稳妥构造函数模式
// 稳妥构造函数遵循与寄生构造函数类似的模式。但有两点不同：
// 一是新创建对象的实例不能引用this
// 二是不使用new调用构造函数

function Person(name, age) {
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.sayName = function () {
        console.log(obj.name);
    }
    return obj;
}

var person1 = Person('tianxia', 666);
person1.sayName();
console.log(person1.name);

function createPerson(name, age) {
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.sayName = function () {
        console.log(this.name);
    }
    return obj;
}
var person = createPerson('tianxia', 18);
console.log(person);

function Person11(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = function () {
        console.log(this.name);
    }
}
var person1 = new Person11('tianxia', 18);
var person2 = new Person11('xiaoxiao', 18);

console.log(person1);
console.log(person2);

console.log(person1.constructor == Person11);
console.log(person2.constructor == Person11);

console.log(person1.__proto__ == Person11.prototype);
console.log(person2.__proto__ == Person11.prototype);

//标示对象类型，即对象实例和构造函数的关系
console.log(person1 instanceof Person11);
console.log(person1 instanceof Object);

console.log(person2 instanceof Person11);
console.log(person2 instanceof Object);

//person1和person2是Person11的两个不同的实例
console.log(person1 == person2);  //false

//不同实例上的同名函数是不相等的
console.log(person1.sayName == person2.sayName); //false

function Person12(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = sayName
}
var person121 = new Person12('tianxia', 1);
var person122 = new Person12('xiaoxiao', 2);

function sayName() {
    console.log(this.name);
}
person121.sayName();

function Per() {}
Per.prototype.name = 'tianxia';
Per.prototype.age = 18;
Per.prototype.sayName = function() {
    console.log(this.name);
}
var person1 = new Per();
person1.name = 'xiaoxiao';
person1.sayName()
var person2 = new Per();
person2.sayName();

console.log(person1.sayName == person2.sayName); //true

//虽然在所有实现中都无法访问到[[prototype]],但可以通过isPrototypeOf()来确定对象之间是否存在这种关系。
console.log(Per.prototype.isPrototypeOf(person1)); //true
console.log(Per.prototype.isPrototypeOf(person2)); //true

//ECMAScript 新增了一个方法，Object.getPrototypeOf(); 获取一个对象的原型值
console.log(Object.getPrototypeOf(person1));
console.log(Object.getPrototypeOf(person2));

console.log(person1.constructor);
//hasOwnProperty()检测一个对象的属性是否存在实例中
console.log(person1.hasOwnProperty('name')); //属性name来自于实例
console.log(person2.hasOwnProperty('name')); //属性name来自于原型

//删除的原型上name还是实例上的name呢？
delete person1.name;
console.log(person1.name);
console.log(person1.hasOwnProperty('name'));


console.log(Object.getOwnPropertyDescriptor(Per.prototype,'name'));
//如何删除原型上的属性

//in单独使用，in操作符会在通过对象能够访问到给定的属性时返回true，不论属性存在实例中还是原型中。
console.log('name' in person1);
console.log('age' in person1);

function hasPrototypeProperty(name,object) {
    return object.hasOwnProperty('name') && (name in object);
}

console.log(hasPrototypeProperty('name',person1)); //false 存在与原型中

for(var prop in person1) {
    console.log(prop);
}
console.log(Object.keys(person1));
console.log(Object.keys(Per.prototype));
console.log(Object.getOwnPropertyNames(Per.prototype));

function Per() {}
Per.prototype = {
    name: 'xiao',
    age: 18,
    sayName: function() {
        console.log(this.name);
    }
}
var person1 = new Per();
console.log(person1.name);
console.log(Per.prototype.constructor); //Object
console.log(person1.constructor); //Object

//字面量对象是否有构造函数
var obj = {
    name: 'xiao',
    age: 18
}
console.log(obj.constructor);

console.log(person1 instanceof Per);
console.log(person1 instanceof Object);

console.log(person1.constrctor == Per);
console.log(person1.constructor == Object);


console.log(Object.getPrototypeOf(person1) == Per.prototype); //true
console.log(Object.prototype.isPrototypeOf(person1));

console.log(Per.prototype.isPrototypeOf(person1)); //true

function PP() {}
PP.prototype = {
    constructor: PP,
    name: 'xiao',
    age: 18,
}
var p1 = new PP();

console.log(p1);
console.log(p1.constructor); //PP
console.log(Object.getOwnPropertyDescriptor(PP.prototype,'constructor'));
for(var prop in p1) {
    console.log(prop);
}
//for-in遍历既包括实例中的属性也包含原型中的。为何？但只遍历原型的话，只能遍历出原型的属性和方法，
// 不能遍历出实例的。
p1.job = 'web前端工程师';
for(var prop in PP.prototype) {
    console.log('for-in',prop);
}
Object.defineProperty(p1,'constructor',{
    enumerable: false,
    value: PP,
});
for(var prop in p1) {
    console.log('遍历之后的结果',prop);
}
console.log(p1.constructor);

function PersonX(){}
var friend = new PersonX();
// PersonX.prototype.sayName = function() {
//     console.log('hi');
// }
//friend.sayName(); //hi

var obj = new Object();
console.log(obj.__proto__);
console.log(Object.prototype);

PersonX.prototype = {
    constructor: PersonX,
    name: 'xiao',
    age: 18,
    sayName: function() {
        console.log('hi');
    }
}
var friend = new PersonX();
console.log(friend.__proto__);
friend.sayName(); //TypeError: friend.sayName is not a function

function PX() {

}
PX.prototype = {
    constructor: PX,
    name: 'xiao',
    age: 18,
    colors: ['yellow','blue']
}
var person1 = new PX();
person1.name = 123;
person1.colors.push('purple');
console.log(person1);
var person2 = new PX;
console.log(person2);

//组合使用构造函数模式和原型模式
function Px1(name,age){
    this.name = name;
    this.age = age;
    this.colors = ['yellow','blue']
}

Px1.prototype = {
    constructor: Px1,
    sayName: function() {
        console.log(this.name);
    }
}

var person1 = new Px1('tianxia',1);
var person2 = new Px1('xiaoxiao',2);

person1.colors.push('green');

console.log(person1.colors); // ["yellow", "blue", "green"]
console.log(person2.colors); // ["yellow", "blue"]

console.log(person1.sayName == person2.sayName); //true
console.log(person1.colors == person2.colors);  //false

//动态原型模式
function Px2(name,age){
    this.name = name;
    this.age = age;
    if(typeof this.sayName != 'function'){
        Px2.prototype.sayName = function(){
            console.log(this.name);
        }
    }
}
var px1 = new Px2('tianxia',1);
var px2 = new Px2('xiaoxiao',2);

px1.sayName();
console.log(px1 instanceof Px2); //true

//寄生构造函数模式
function Px3(name,age) {
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.sayName = function(){
        console.log(this.name);
    }
    return obj;
}
var px1 = new Px3('xiao',18);
var px2 = new Px3('tianxia',22);
console.log(px1);
console.log(px2);
console.log(px1 instanceof Px3); //false

function SpecialArray(){
    var values = new Array();
    values.push.apply(values,arguments);
    values.toPipedString = function() {
        return this.join('|');
    }
    return values;
}
var colors = new SpecialArray('red','blue','yellow');

console.log(colors.__proto__);
console.log(colors.__proto__ == SpecialArray.prototype); //false
console.log(colors instanceof SpecialArray); //false

console.log(colors.toPipedString()); //red|blue|yellow

//稳妥构造函数模式
function Px4(name,age){
   var o = new Object();
   o.sayName = function() {
       console.log(name);
   }
   return o;
}
var px4 = Px4('tianxia666',18);
px4.sayName();
console.log(px4 instanceof Px4); //false

function SpecialArray(){
    var values = new Array();
    values.push.apply(values,arguments);
    console.log(values);
    values.toPipedString = function(){
        return values.join('|');
    }
    return values;
}
var res = new SpecialArray('yellow','blue','green');
console.log(res.toPipedString());

function Px5(name,age){
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    return obj;
}
var px5 = new Px5('tianxia666',666);
console.log(px5);
console.log(px5.constructor); //Object
console.log(px5.__proto__); //Object的原型

function Px6(){}
var px6 = new Px6();
console.log(px6.constructor);

function Px7(name,age){
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    return obj;
}
var px7 = new Px7('tianxia',666);
console.log(px7.constructor); //Object
*/
class Mode extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div>
                Mode
            </div>
        )
    }
}
export default Mode;